package sncf.utils;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;

import sncf.client.User;
import sncf.server.TrainUrl;

public class ConfigLoader {

	// FIELDS
	private static final String CONF_FILE_PATH = System.getProperty("user.dir")
			+ "/resources/conf.xml";

	private static final int DEFAULT_REFRESH_MINUTES = 30;
	private static final int DEFAULT_MAX_MINUTES_LATE = 30;
	private static final String DEFAULT_SAVE_TIME = "02h00mn";
	private static final String DEFAULT_WORKING_DIR = "C:\\SncfDumper\\dump\\";
	private static final Map<String, TrainUrl> DEFAULT_TRAIN_URL_MAP = new HashMap<String, TrainUrl>();
	static {
		String garekey = "PARIS_ST_LAZARE";
		String gareName = "Paris Saint Lazare";
		String gareUrl = "http://www.gares-en-mouvement.com/fr/frpsl/horaires-temps-reel/arr/";
		TrainUrl trainUrl = new TrainUrl();
		trainUrl.setName(gareName);
		trainUrl.setUrl(gareUrl);

		ConfigLoader.DEFAULT_TRAIN_URL_MAP.put(garekey, trainUrl);
	}

	public static final String TRAIN_URL_MAP_PROPERTY = "trainUrlMap";
	public static final String WORKING_DIR_PROPERTY = "workingDir";
	public static final String REFRESH_MINUTES_PROPERTY = "refreshMinutes";
	public static final String MAX_MINUTES_LATE_PROPERTY = "maxMinutesLate";
	public static final String SAVE_TIME_PROPERTY = "saveTime";
	public static final String FROM_FILTER_PROPERTY = "fromFilter";
	public static final String TRAIN_NUMBER_FILTER_PROPERTY = "trainNumberFilter";
	public static final String PROXY_HOST_ADDRESS_PROPERTY = "hostAddress";
	public static final String PROXY_HOST_PORT_PROPERTY = "hostPort";
	public static final String PROXY_USER_LOGIN_PROPERTY = "login";
	public static final String PROXY_USER_PASSWORD_PROPERTY = "password";
	public static final String PROXY_AUTO_CONFIG_PROPERTY = "autoConfig";
	public static final String USER_ALERT_LIST_PROPERTY = "userAlertList";
	public static final String LATE_CONFIRMATION_SERVICE_PROPERTY = "LateConfirmation";

	private static ConfigLoader instance;

	private Map<String, Object> configMap;

	// CONSTRUCTORS
	private ConfigLoader() {
		this.configMap = new HashMap<String, Object>();
		loadConfig();
	}

	// METHODS
	public static synchronized ConfigLoader getInstance() {
		if (instance == null) {
			instance = new ConfigLoader();
		}

		return instance;
	}

	public Object get(String propertyName) {
		return configMap.get(propertyName);
	}

	private void loadConfig() {
		Map<String, TrainUrl> trainUrlMap = new HashMap<String, TrainUrl>();
		String dirPath = ConfigLoader.DEFAULT_WORKING_DIR;
		int refreshMinutes = ConfigLoader.DEFAULT_REFRESH_MINUTES;
		int maxMinutesLate = ConfigLoader.DEFAULT_MAX_MINUTES_LATE;
		String saveTimeString = ConfigLoader.DEFAULT_SAVE_TIME;
		Map<String, List<String>> filterFromMap = new HashMap<String, List<String>>();
		Map<String, List<String>> filterTrainNumberMap = new HashMap<String, List<String>>();
		List<User> userAlertList = new ArrayList<User>();

		Document doc = getDocument();

		Element rootElement = doc.getRootElement();
		if (rootElement != null
				&& "root".equalsIgnoreCase(rootElement.getName())) {

			// load gare list
			Element gareListElement = rootElement.getChild("gareList");
			if (gareListElement != null) {
				List<Element> gareElementList = gareListElement
						.getChildren("gare");

				if (gareElementList != null) {
					for (Element gareElement : gareElementList) {
						String key = gareElement.getAttributeValue("key");
						if (key != null && !trainUrlMap.containsKey(key)) {
							TrainUrl trainUrl = new TrainUrl();

							String gareName = gareElement
									.getAttributeValue("name");
							String gareUrl = gareElement
									.getAttributeValue("url");

							trainUrl.setName(gareName);
							trainUrl.setUrl(gareUrl);

							trainUrlMap.put(key, trainUrl);
						}

						Element filterElement = gareElement.getChild("filter");
						List<String> filterFromList = new ArrayList<String>();
						List<String> filterTrainNumberList = new ArrayList<String>();
						if (filterElement != null) {

							// load from filter
							Element fromFilterElement = filterElement
									.getChild("from_filter");

							if (fromFilterElement != null) {
								List<Element> fromList = fromFilterElement
										.getChildren("from");
								if (fromList != null) {
									for (Element fromElement : fromList) {
										filterFromList.add(fromElement
												.getAttributeValue("name")
												.replaceAll(" ", "")
												.toLowerCase());
									}
								}
							}

							// load train number filter
							Element trainNumberFilterElement = filterElement
									.getChild("train_number_filter");
							if (trainNumberFilterElement != null) {
								List<Element> trainNumberList = trainNumberFilterElement
										.getChildren("train_number");
								if (trainNumberList != null) {
									for (Element trainNumberElement : trainNumberList) {
										filterTrainNumberList
												.add(trainNumberElement
														.getAttributeValue("pattern"));
									}
								}
							}
						}
						filterFromMap.put(key, filterFromList);
						filterTrainNumberMap.put(key, filterTrainNumberList);
					}

				}
			}

			// load proxy parameters
			Element proxyElement = rootElement.getChild("proxy");
			if (proxyElement != null) {
				String hostAddress = proxyElement
						.getAttributeValue("hostAddress");
				if (hostAddress != null) {
					this.configMap.put(
							ConfigLoader.PROXY_HOST_ADDRESS_PROPERTY,
							hostAddress);
				}

				String hostPort = proxyElement.getAttributeValue("hostPort");
				if (hostPort != null) {
					this.configMap.put(ConfigLoader.PROXY_HOST_PORT_PROPERTY,
							hostPort);
				}

				Element authElement = proxyElement.getChild("auth");
				if (authElement != null) {
					String login = authElement.getAttributeValue("login");
					String password = authElement.getAttributeValue("password");

					if (login != null && password != null) {
						this.configMap.put(
								ConfigLoader.PROXY_USER_LOGIN_PROPERTY, login);
						this.configMap.put(
								ConfigLoader.PROXY_USER_PASSWORD_PROPERTY,
								password);
					}
				}

				Element autoConfigElement = proxyElement
						.getChild(PROXY_AUTO_CONFIG_PROPERTY);
				if (autoConfigElement != null) {
					String autoConfig = autoConfigElement
							.getAttributeValue("name");
					if (autoConfig != null) {
						this.configMap.put(
								ConfigLoader.PROXY_AUTO_CONFIG_PROPERTY,
								autoConfig);
					}
				}
			}

			// load additional services
			Element additionalServicesMainTag = rootElement
					.getChild("additional_services");
			if (additionalServicesMainTag != null) {
				List<Element> services = additionalServicesMainTag
						.getChildren("service");
				if (services != null && !services.isEmpty()) {
					for (Element serviceElement : services) {
						boolean activate = false;
						String activateText = serviceElement
								.getAttributeValue("activate");

						if (activateText != null) {
							activate = Boolean.parseBoolean(activateText);
						}

						String serviceName = serviceElement
								.getAttributeValue("name");

						if (serviceName != null && !serviceName.isEmpty()) {
							this.configMap.put(serviceName, activate);
						}
					}
				}
			}

			// load preferences
			Element prefsElement = rootElement.getChild("prefs");
			if (prefsElement != null) {
				Element dirElement = prefsElement.getChild("dir");
				Element refreshMinutesElement = prefsElement
						.getChild("refreshMinutes");
				Element maxMinutesLateElement = prefsElement
						.getChild("maxMinutesLate");
				Element saveTimeElement = prefsElement.getChild("saveTime");

				Element userAlertListElement = prefsElement
						.getChild("userAlertList");
				if (userAlertListElement != null
						&& !userAlertListElement.getChildren().isEmpty()) {
					List<Element> userElementList = userAlertListElement
							.getChildren("user");
					if (userElementList != null && !userElementList.isEmpty()) {
						for (Element userElement : userElementList) {
							String name = userElement.getAttributeValue("name");
							String email = userElement
									.getAttributeValue("email");

							User user = new User(name, email);
							userAlertList.add(user);
						}
					}
				}

				if (dirElement != null) {
					String path = dirElement.getAttributeValue("path");
					if (path != null && !path.isEmpty()) {
						dirPath = path;
					} else {
						dirPath = DEFAULT_WORKING_DIR;
					}
				} else {
					dirPath = DEFAULT_WORKING_DIR;
				}

				if (saveTimeElement != null
						&& saveTimeElement.getAttributeValue("value") != null) {
					saveTimeString = saveTimeElement.getAttributeValue("value");
				}

				try {
					refreshMinutes = refreshMinutesElement != null ? Integer
							.parseInt(refreshMinutesElement
									.getAttributeValue("value"))
							: ConfigLoader.DEFAULT_REFRESH_MINUTES;
				} catch (NumberFormatException e) {
					e.printStackTrace();
					refreshMinutes = ConfigLoader.DEFAULT_REFRESH_MINUTES;
				}

				try {
					maxMinutesLate = maxMinutesLateElement != null ? Integer
							.parseInt(maxMinutesLateElement
									.getAttributeValue("value"))
							: ConfigLoader.DEFAULT_MAX_MINUTES_LATE;
				} catch (NumberFormatException e) {
					e.printStackTrace();
					maxMinutesLate = ConfigLoader.DEFAULT_MAX_MINUTES_LATE;
				}
			}
		}

		if (trainUrlMap == null || trainUrlMap.isEmpty()) {
			trainUrlMap = ConfigLoader.DEFAULT_TRAIN_URL_MAP;
		}

		this.configMap.put(ConfigLoader.TRAIN_URL_MAP_PROPERTY, trainUrlMap);
		this.configMap.put(ConfigLoader.WORKING_DIR_PROPERTY, dirPath);
		this.configMap.put(ConfigLoader.REFRESH_MINUTES_PROPERTY,
				refreshMinutes);
		this.configMap.put(ConfigLoader.MAX_MINUTES_LATE_PROPERTY,
				maxMinutesLate);
		this.configMap.put(ConfigLoader.SAVE_TIME_PROPERTY, saveTimeString);
		this.configMap.put(ConfigLoader.FROM_FILTER_PROPERTY, filterFromMap);
		this.configMap.put(ConfigLoader.TRAIN_NUMBER_FILTER_PROPERTY,
				filterTrainNumberMap);
		this.configMap
				.put(ConfigLoader.USER_ALERT_LIST_PROPERTY, userAlertList);
	}

	private Document getDocument() {
		Document doc = null;

		try {
			SAXBuilder builder = new SAXBuilder();
			File file = new File(CONF_FILE_PATH);
			doc = builder.build(file);
		} catch (JDOMException | IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return doc;
	}

	public boolean isLateConfirmationServiceActivate() {
		Boolean lateConfirmationServiceActivated = (Boolean) ConfigLoader
				.getInstance().get(
						ConfigLoader.LATE_CONFIRMATION_SERVICE_PROPERTY);
		boolean confirmationActivated = lateConfirmationServiceActivated != null ? lateConfirmationServiceActivated
				: false;

		return confirmationActivated;
	}

}
